// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// IR访客在IR树上行走。
// 
// 最底层的帮助者是DoChildren和EditChildren，这些节点帮助实现并控制在IR行走期间是否以及何时发生
// 递归。
// 
// 虽然这两种模式都直接有用，但两种更简单的模式
// 非常常见，并且也提供了：Visit和Any。

package ir

// DoChildren在n的每个非零子节点x上调用do（x）。
// 如果任何调用返回true，DoChildren将停止并返回true。
// 否则，DoChildren返回false。注意：只给孩子打电话。
// 如果x的孩子需要处理，则do（x）必须呼叫DoChildren（x，do）。
// 
// DoChildren允许构造IR图的一般遍历
// 如果需要，可以提前停止。最常用的用法是：
// 
// var do func（ir.Node）bool 
// do=func（x ir.Node）bool{
// …探视儿童前的处理…
// …如果…应该探视儿童…{
// ir.DoChildren x，do）
// return true 
// }
// return false 
// }
// do（root）
// 
// 由于DoChildren本身不返回true，如果do函数
// 永远不想停止遍历，它可以假定DoChildren 
// 本身将始终返回false，简化为：
// 
// var do func（ir.Node）bool 
// do=func（x ir.Node）bool{
// …在探视儿童之前进行处理…
// /如果…应该探视儿童…{。。。探望孩子后的处理。。。
// return false 
// }
// do（root）
// 
// Visit函数进一步简化了模式，
// 仅在访问儿童之前进行处理，并且永不停止：
// 
// 函数访问（n ir.Node，Visit func（ir.Node））{
// 如果n==nil{
// 返回
// /}
// var do func（ir.Node）bool 
// 返回ir。DoChildren（x，do）
// }
// do（n）
// }
// 
// Any函数说明了模式的不同简化，
// 递归地访问每个节点，然后访问其子节点，直到找到一个cond（x）返回true的节点x，此时，整个
// 遍历停止并返回true。
// 
// func Any（n ir.Node，cond（ir.Node）bool{
// if n==nil{
// return false 
// }
// var do func（ir.Node）bool 
// do=func（x ir.Node）bool{
// 
// Visit和Any是如何有效地使用
// DOCHILDEN的例子，但当然，如果使用
// Visit或Any捕获的简化，直接调用本软件包提供的内容，将得到最好的服务。
func DoChildren(n Node, do func(Node) bool) bool {
	if n == nil {
		return false
	}
	return n.doChildren(do)
}

// Visit以深度优先的前序遍历方式访问以n为根的IR树中的每个非零节点x，在访问的每个节点上调用Visit。shu jian defg
func Visit(n Node, visit func(Node)) {
	if n == nil {
		return
	}
	var do func(Node) bool
	do = func(x Node) bool {
		visit(x)
		return DoChildren(x, do)
	}
	do(n)
}

func VisitList(list Nodes, visit func(Node)) {
	for _, x := range list {
		Visit(x, visit)
	}
}

// Any在以n 
// 为根的IR树中查找非nil节点x，其cond（x）返回true。
// 任何节点都会以深度优先、前序遍历的方式考虑节点。
// 当Any找到一个节点x，使得cond（x）为true时，
// Any结束遍历并立即返回true。
// 否则，在完成整个遍历后，Any返回false。
func Any(n Node, cond func(Node) bool) bool {
	if n == nil {
		return false
	}
	var do func(Node) bool
	do = func(x Node) bool {
		return cond(x) || DoChildren(x, do)
	}
	return do(n)
}

// AnyList按顺序为列表中的每个节点x调用Any（x，cond）。
// 如果任何调用返回true，AnyList将停止并返回true。
// 否则，AnyList在为列表中的每个x调用Any（x，cond）
// 后返回false。
func AnyList(list Nodes, cond func(Node) bool) bool {
	for _, x := range list {
		if Any(x, cond) {
			return true
		}
	}
	return false
}

// EditChildren编辑n的子节点，将每个子节点x替换为edit（x）。
// 
// 注意，EditChildren（n，edit）只为n的直接子代调用edit（x）。
// 如果应该处理x的子项，则edit（x）必须调用EditChildren（x，edit）。
// 
// EditChildren允许构建IR图的一般编辑过程。
// 最常用的用法是：
// 
// var edit func（ir.Node）ir。节点
// edit=func（x ir.Node）ir。节点{
// …编辑子项之前的处理…
// 如果…应该编辑子项…{
// /编辑子项（x，编辑）
// …编辑子项之后的处理…
// }
// 。。。返回x。。。
// }
// n=edit（n）
// 
// EditChildren在位编辑节点。要编辑副本，请先调用copy。例如，一个简单的深度复制实现是：
// 
// func deepCopy（n ir.Node）ir。节点{
// var edit func（ir.Node）ir.Node 
// edit=func（x ir.Node）ir.Node{
// x=ir.Copy（x）
// ir.EditChildren（x，edit）
// return x 
func EditChildren(n Node, edit func(Node) Node) {
	if n == nil {
		return
	}
	n.editChildren(edit)
}
